/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package trace;

/**
 *
 * @author phil
 */
public class TournamentPredictor implements Runnable {

    private int M_BIT = 0x1fff;
    private Reader traceFile;
    private Writer outputFile;

    private int[] branchMisprediction;
    private int[] branchCount;
    private int count = 0, misPrediction = 0;

    private TBranch[] localHistoryTable;
    private Branch[] localPredictTable;

    private Branch[] localNBitPredictor;

    private Branch[] choicePredictTable;
    private int bits=0;

    public TournamentPredictor(Reader iFile, Writer oFile, int n ) {
        this.traceFile = iFile;
        this.outputFile = oFile;
        this.bits = n;
        localHistoryTable = new TBranch[M_BIT + 1];
        for (int i = 0; i < localHistoryTable.length; i++)
            localHistoryTable[i] = new TBranch(8);

        localPredictTable = new Branch[1<<8];
        for (int i = 0; i < localPredictTable.length; i++)
            localPredictTable[i] = new Branch(n);

        localNBitPredictor = new Branch[M_BIT + 1];
        for (int i = 0; i < localNBitPredictor.length; i++)
            localNBitPredictor[i] = new Branch(n);

        choicePredictTable = new Branch[M_BIT + 1];
        for (int i = 0; i < choicePredictTable.length; i++)
            choicePredictTable[i] = new Branch(2);

        branchCount = new int[M_BIT+1];
        branchMisprediction = new int[M_BIT+1];
    }

    public void run() {
        String traceStr;
        String[] fileOption = new String[2];
        traceStr = traceFile.readLine();
        int index,outcome, prediction, localpredicttable_index;
        long address;
        System.out.println("Starting tournament " + traceFile.filename + " " + this.bits);
        while((traceStr != null)){
            fileOption = Reader.parseString(traceStr);
            address = Long.parseLong(fileOption[0]);
            outcome = Integer.parseInt(fileOption[1]);
            index = (int) (address & M_BIT);

            if (choicePredictTable[index].getPrediction() == 0) {
                // Local history
                localpredicttable_index = localHistoryTable[index].getHistoryRegister();
                prediction = localPredictTable[localpredicttable_index].getPrediction();

                //update the stuff
                localHistoryTable[index].updateRegister(outcome);
                localPredictTable[localpredicttable_index].predictionBufferUpdate(outcome);

                if (prediction == outcome) choicePredictTable[index].decrementBuffer();
                else choicePredictTable[index].incrementBuffer();

            } else {
                // Global history
                prediction = localNBitPredictor[index].getPrediction();

                //update
                localNBitPredictor[index].predictionBufferUpdate(outcome);
                if (prediction == outcome) choicePredictTable[index].incrementBuffer();
                else choicePredictTable[index].decrementBuffer();
            }

            //choicePredictTable[index].predictionBufferUpdate(outcome);

            // Update all Buffers & registers

            if (prediction != outcome) branchMisprediction[index]++;

            if (prediction != outcome) misPrediction++;
            count++;

            branchCount[index]++;

            traceStr = traceFile.readLine();
        }
        System.out.println("Done running tournament " + traceFile.filename);
        this.summary();
        outputFile.close();
    }


    public void summary(){
        this.outputFile.writeToFile("Index,Misprediction,Count");
        int lcount = 1;
        for(int i = 0; i < branchCount.length; i++){
            if(this.branchCount[i] != 0){
                lcount++;
                this.outputFile.writeToFile(i + "," + this.branchMisprediction[i] + "," + this.branchCount[i]);
            }
        }
        this.outputFile.writeToFile("," + misPrediction + "," + count + "," + "=B"+(lcount+1)+"/C"+(lcount+1)+"*100");
    }
}
